package org.simplextensions.registry;

import org.simplextensions.annotations.ExtensionStyle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Tomasz Krzyzak, <a
 *         href="mailto:tomasz.krzyzak@gmail.com">tomasz.krzyzak@gmail.com</a>
 * @since 2009-08-17 22:33:16
 * 
 */
public class ConfigurableElem {

	private static final Logger log = LoggerFactory.getLogger(ConfigurableElem.class);

	private Map<String, PropertyValue> propertiesMap = new HashMap<String, PropertyValue>();

	private String id;

	private Class<?> clazz;

	private ExtensionStyle extensionStyle;

	private String factoryMethodName;

	private String[] depends = new String[] {};

	private final IExtensionRegistry extensionRegistry;

	private String className;

	private final SimpleXtensionsBundle bundle;

	public ConfigurableElem(SimpleXtensionsBundle bundle, String id) {
		this.bundle = bundle;
		this.id = id;
		this.extensionRegistry = bundle.getExtensionRegistry();
		this.extensionStyle = ExtensionStyle.PROTOTYPE;
	}

	public ConfigurableElem(SimpleXtensionsBundle bundle, Object executable, String id) {
		this.extensionRegistry = bundle.getExtensionRegistry();
		this.bundle = bundle;
		this.executable = executable;
		this.id = id;
		this.extensionStyle = ExtensionStyle.USER;
		this.clazz = executable.getClass();
		this.className = this.clazz.getCanonicalName();
	}

	public ConfigurableElem(SimpleXtensionsBundle bundle, String className, String id) {
		this.extensionRegistry = bundle.getExtensionRegistry();
		this.bundle = bundle;
		this.className = className;
		this.id = id;
	}

	public ConfigurableElem(SimpleXtensionsBundle bundle, String className, String id,
			ExtensionStyle extensionStyle, String factoryMethodName) {
		this.extensionRegistry = bundle.getExtensionRegistry();
		this.bundle = bundle;
		this.className = className;
		this.id = id;
		this.extensionStyle = extensionStyle;
		this.factoryMethodName = factoryMethodName;

	}

	/**
	 * 
	 * @param propertyName
	 * @param propertyValue
	 */
	public void setPropertyValue(String propertyName, PropertyValue propertyValue) {
		PropertyValue removed = this.propertiesMap.remove(propertyName);
		if (removed != null) {
			if (log.isWarnEnabled()) {
				log.warn("replacing attribute's " + propertyName);
			}
		}
		this.propertiesMap.put(propertyName, propertyValue);
	}

	/**
	 * 
	 * @param propertyName
	 * @return
	 */
	public PropertyValue getPropertyValue(String propertyName) {
		return this.propertiesMap.get(propertyName);
	}

	/**
	 * @param id
	 *            the id to set
	 */
	public void setId(String id) {
		this.id = id;
	}

	/**
	 * 
	 * @return
	 */
	public Collection<String> getPropertyNames() {
		return Collections.unmodifiableCollection(this.propertiesMap.keySet());
	}

	protected Object executable = null;

	public synchronized Object getExecutable() {
		if (this.executable == null) {
			return this.getExtensionRegistry().createExecutable(this);
		}
		return this.executable;
	}

	private boolean intialized;

	public boolean isInitialized() {
		return intialized;
	}

	void setInitialized(boolean initialized) {
		intialized = initialized;
	}

	/**
	 * @return the factoryMethodName
	 */
	public String getFactoryMethodName() {
		return factoryMethodName;
	}

	/**
	 * @param factoryMethodName
	 *            the factoryMethodName to set
	 */
	void setFactoryMethodName(String factoryMethodName) {
		this.factoryMethodName = factoryMethodName;
	}

	/**
	 * @return the id
	 */
	public String getId() {
		return id;
	}

	/**
	 * @return the clazz
	 */
	public Class<?> getClazz() {
		if (clazz == null) {
			try {
				this.clazz = Class.forName(className);
				log.trace("!!!!!!! creating class of " + getClass().getSimpleName() + ": " + className);
			} catch (Exception e) {
				throw new RuntimeException("id: " + id + ", className: " + className + ", ", e);
			}
		}
		return clazz;
	}

	public String getClassName() {
		return this.className;
	}

	/**
	 * @return the extensionStyle
	 */
	public ExtensionStyle getExtensionStyle() {
		return extensionStyle;
	}

	void setDepends(String[] depends) {
		this.depends = depends;
	}

	public String[] getDepends() {
		return depends;
	}

	public IExtensionRegistry getExtensionRegistry() {
		return extensionRegistry;
	}

	public SimpleXtensionsBundle getBundle() {
		return bundle;
	}
	
	public String toString(){
		StringBuilder sb = new StringBuilder();
		sb.append("id: ").append(id);
		return sb.toString();
	}

}
